#include <jni.h>
#include <stdlib.h>

#include <android/log.h> /* for debugging */

#include "haptimap_internal.h" /* needed to access hm->platform_init_privdata */
#include "haptimap_android_jni.h"
#include "common.h"

/*
 * Class:     org_haptimap_HaptiMap
 * Method:    LocationSensorInquire
 * Signature: ([I)I
 */
jint Java_org_haptimap_HaptiMap_LocationSensorInquire
  (JNIEnv *env, jobject wrapper, jintArray ptr_count)
{
    hm_t *hm = GET_HM(wrapper);
    int count;

    if(hm_location_sensor_inquire(hm, &count) != HM_SUCCESS)
        return HM_FAILURE;

    STORE_INT(ptr_count, count);

    return HM_SUCCESS;
}

/*
 * Class:     org_haptimap_HaptiMap
 * Method:    LocationSensorGetId
 * Signature: (I[I)I
 */
jint Java_org_haptimap_HaptiMap_LocationSensorGetId
  (JNIEnv *env, jobject wrapper, jint n, jintArray ptr_id)
{
    hm_t *hm = GET_HM(wrapper);
    int id;

    if(hm_location_sensor_get_id(hm, n, &id) != HM_SUCCESS)
        return HM_FAILURE;

    STORE_INT(ptr_id, id);

    return HM_SUCCESS;
}

/*
 * Class:     org_haptimap_HaptiMap
 * Method:    LocationSensorGetAttribute
 * Signature: (ILorg/haptimap/HaptiMap/ATTRIBUTE;[I)I
 */
jint Java_org_haptimap_HaptiMap_LocationSensorGetAttribute
  (JNIEnv *env, jobject wrapper, jint id, jobject att, jintArray ptr_val)
{
    hm_t *hm = GET_HM(wrapper);
    int val;

    if(hm_location_sensor_get_attribute(hm, id, GET_ORDINAL(att), &val) != HM_SUCCESS)
        return HM_FAILURE;

    STORE_INT(ptr_val, val);

    return HM_SUCCESS;
}

/*
 * Class:     org_haptimap_HaptiMap
 * Method:    LocationSensorGetAttributeString
 * Signature: (ILorg/haptimap/HaptiMap/ATTRIBUTE;Ljava/lang/StringBuilder;)I
 */
jint Java_org_haptimap_HaptiMap_LocationSensorGetAttributeString
  (JNIEnv *env, jobject wrapper, jint id, jobject att, jobject str_val)
{
    hm_t *hm = GET_HM(wrapper);
    const char *val;
    jstring str;

    if(hm_location_sensor_get_attribute_string(hm, id, GET_ORDINAL(att), &val) != HM_SUCCESS)
        return HM_FAILURE;

    /* First convert C string to Java string */
    str = (*env)->NewStringUTF(env, val);
    /* Then append this Java string to the StringBuilder object */
    (*env)->CallObjectMethod(env, str_val, (*env)->GetMethodID(env, (*env)->GetObjectClass(env, str_val), 
                                                               "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;"),
                             str);

    return HM_SUCCESS;
}

/*
 * Class:     org_haptimap_HaptiMap
 * Method:    LocationSensorInitialise
 * Signature: (I)I
 */
jint Java_org_haptimap_HaptiMap_LocationSensorInitialise
  (JNIEnv *env, jobject wrapper, jint id)
{
    hm_t *hm = GET_HM(wrapper);

    return hm_location_sensor_init(hm, id);
}

/*
 * Class:     org_haptimap_HaptiMap
 * Method:    LocationSensorUninitialise
 * Signature: (I)I
 */
jint Java_org_haptimap_HaptiMap_LocationSensorUninitialise
  (JNIEnv *env, jobject wrapper, jint id)
{
    hm_t *hm = GET_HM(wrapper);

    return hm_location_sensor_uninit(hm, id);
}

/*
 * Class:     org_haptimap_HaptiMap
 * Method:    LocationSensorDefineCallback
 * Signature: (ILorg/haptimap/HaptiMap/EVENT_TYPE;Lorg/haptimap/HaptiMap/HaptiMapCallbackType;)I
 */
jint Java_org_haptimap_HaptiMap_LocationSensorDefineCallback
  (JNIEnv *env, jobject wrapper, jint id, jobject event, jobject cb_interface)
{
    hm_t *hm = GET_HM(wrapper);

    return hm_location_sensor_callback_define(hm, id, GET_ORDINAL(event), hm_jni_callback_wrapper, 
					      (*env)->NewGlobalRef(env, cb_interface));
}

/*
 * Class:     org_haptimap_HaptiMap
 * Method:    LocationSensorCancelCallback
 * Signature: (ILorg/haptimap/HaptiMap/EVENT_TYPE;)I
 */
jint Java_org_haptimap_HaptiMap_LocationSensorCancelCallback
  (JNIEnv *env, jobject wrapper, jint id, jobject event)
{
    hm_t *hm = GET_HM(wrapper);

    /* There will be a memory leak here as we don't delete the global reference to the
     * callback interface class. */
    return hm_location_sensor_callback_cancel(hm, id, GET_ORDINAL(event));
}

/*
 * Class:     org_haptimap_HaptiMap
 * Method:    LocationSensorGetLocation
 * Signature: (I[I[I)I
 */
jint Java_org_haptimap_HaptiMap_LocationSensorGetLocation
  (JNIEnv *env, jobject wrapper, jint id, jintArray ptr_location, jintArray ptr_is_3d)
{
    hm_t *hm = GET_HM(wrapper);
    int location[3];
    int is_3d;

    if(hm_location_sensor_get_location(hm, id, location, &is_3d) != HM_SUCCESS)
        return HM_FAILURE;

    (*env)->SetIntArrayRegion(env, ptr_location, 0, 3, location);
    STORE_INT(ptr_is_3d, is_3d);

    return HM_SUCCESS;
}

/*
 * Class:     org_haptimap_HaptiMap
 * Method:    LocationSensorGetLocationWGS84
 * Signature: (I[D[I)I
 */
jint Java_org_haptimap_HaptiMap_LocationSensorGetLocationWGS84
  (JNIEnv *env, jobject wrapper, jint id, jdoubleArray ptr_location, jintArray ptr_is_3d)
{
    hm_t *hm = GET_HM(wrapper);
    double location[3];
    int is_3d;

    if(hm_location_sensor_get_location_wgs84(hm, id, location, &is_3d) != HM_SUCCESS)
        return HM_FAILURE;

    (*env)->SetDoubleArrayRegion(env, ptr_location, 0, 3, location);
    STORE_INT(ptr_is_3d, is_3d);

    return HM_SUCCESS;
}
